﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Snowdreamist.Windows.Navigation.Primitives;

namespace Snowdreamist.Windows.Navigation
{
    public class Session : NavigationJournal
    {
        public Session(NavigationService service)
        {
            if (service == null)
                throw new ArgumentNullException("service");
            this.Service = service;
        }

        public bool IsActive
        {
            get
            {
                var presenter = this.Service.Presenter.GetSessionPresenter(this);
                return presenter != null ? presenter.IsActived : false;
            }
        }

        public NavigationService Service { get; private set; }

        public virtual void Active()
        {
            var presenter = this.Service.Presenter.GetSessionPresenter(this);
            if (presenter != null)
                presenter.Active();
        }

        public virtual void Close()
        {
            this.Service.CloseSession(this);
        }

        public virtual bool NavigateTo(Uri uri)
        {
            // create entry
            NavigationJournalEntry entry = new NavigationJournalEntry(this, uri, false, null);
            return this.NavigateTo(entry);
        }

        public event EventHandler<JournalChangedEventArgs<MetaJournalEntry>> MetaJournalChanged;

        public event EventHandler Navigated;

        #region Handle real navigation changed

        protected override void OnJournalChanged(NavigationJournalEntry newEntry)
        {
            base.OnJournalChanged(newEntry);

            if (!newEntry.IsSavedFrame || newEntry.Frame == null || newEntry.Frame.ContentView == null)
            {
                // create new frame
                if (newEntry.Frame == null)
                    newEntry.Frame = new SessionFrame();
                // process request
                var processor = this.Service.CreateNavigateProcessor(this);

                processor.RequestUri = newEntry.Uri;
                processor.ViewModel = newEntry.Frame != null ? newEntry.Frame.ContentViewModel : null;

                try
                {
                    if (!processor.Process())
                        throw new InvalidOperationException("Process request failed");
                    // assign to frame
                    newEntry.Frame.ContentView = processor.View;
                    newEntry.Frame.ContentViewModel = processor.ViewModel;
                }
                catch (Exception error)
                {
                    if (this.Service.ErrorHandler != null)
                    {
                        using (var context = processor.GetContext(error))
                        {
                            this.Service.ErrorHandler.ProcessRequest(context);
                        }
                        // assign to frame
                        newEntry.Frame.ContentView = processor.View;
                        newEntry.Frame.ContentViewModel = processor.ViewModel;
                        // donot save error content
                        // thus, when refresh, content will be reloaded
                        newEntry.IsSavedFrame = false;
                    }
                }
            }

            this.OnNavigated();
        }

        protected virtual void OnNavigated()
        {
            if (this.Navigated != null)
                this.Navigated(this, new EventArgs());
        }

        internal override void OnMetaJournalChanged(MetaJournalEntry metaEntry)
        {
            // notify
            if (this.MetaJournalChanged != null)
                this.MetaJournalChanged(this, new JournalChangedEventArgs<MetaJournalEntry>(metaEntry));
        }

        #endregion Handle real navigation changed
    }
}